use serde::Serialize;
use crate::named::Named;

pub struct RpcSequence<S> {
    local_seq: u64,
    remote_seq: u64,
    source: S,
}

pub struct RpcRequest<S> {
    method: String,
    params: Vec<u8>,

    sequence: RpcSequence<S>,
}

pub enum RpcResponseStatus {
    Success(Vec<u8>),
    Error,
}

pub struct RpcResponse<S> {
    result: RpcResponseStatus,

    sequence: RpcSequence<S>,
}

pub trait RpcResponser<S> {
    fn respond(&self, response: RpcResponse<S>);
}

pub trait SyncRpcHandler<S> {
    fn handle(&self, request: RpcRequest<S>) -> RpcResponse<S>;
}

pub trait AsyncRpcHandler<S> {
    fn handle<R>(&self, request: RpcRequest<S>, responder: R) -> RpcRequest<S> where R: RpcResponser<S>;
}

pub trait CallAble {
    type Output : serde::Serialize + serde::de::DeserializeOwned + Send;
    type Params : serde::Serialize + serde::de::DeserializeOwned + Send;
}

#[async_trait::async_trait]
pub trait RpcClient<L> {
    async fn call<T>(&mut self, location: Option<L>, params: T::Params) -> tokio::io::Result<T::Output>
        where T: Named + CallAble;
    fn async_call<T, F>(&mut self, location: Option<L>, params: T::Params, call_back: F) -> tokio::io::Result<()>
        where T: Named + CallAble, F: FnOnce(tokio::io::Result<T::Output>) -> ();
}

#[async_trait::async_trait]
pub trait RpcServer {
    fn register_handler<H>(&mut self, handler: H)
        where H: RpcHandler + Send + Sync + 'static;

    async fn serve(&mut self) -> tokio::io::Result<()>;
}

#[async_trait::async_trait]
pub trait RpcHandler : Default + Send + Sync + 'static {
    fn register<S>(server: &mut S) where S: RpcServer {
        server.register_handler(Self::default());
    }
    
    async fn handle(&self, params: &[u8]) -> tokio::io::Result<Option<Vec<u8>>>;
}

#[async_trait::async_trait]
pub trait RpcCall : CallAble + Default + Send + Sync + 'static {
    async fn call(&self, params: Self::Params) -> tokio::io::Result<Self::Output>;
}

#[async_trait::async_trait]
impl<C> RpcHandler for C where C : RpcCall {
    async fn handle(&self, params: &[u8]) -> tokio::io::Result<Option<Vec<u8>>> {
        let params = rmp_serde::from_slice(&params).map_err(|e| tokio::io::Error::new(tokio::io::ErrorKind::InvalidData, e))?;
        let output = self.call(params).await?;
        if std::any::TypeId::of::<<Self as CallAble>::Output>() == std::any::TypeId::of::<()>() {
            Ok(None)
        } else {
            let mut buf = Vec::new();
            output.serialize(&mut rmp_serde::encode::Serializer::new(&mut buf)).unwrap();

            Ok(Some(buf))
        }
    }
}
